package t2.client;


import java.util.LinkedList;
import java.util.Queue;

import t2.client.events.LocalATcmdEvent;
import t2.client.events.LocalATcmdEventHandler;
import t2.client.events.RemoteAtCmdEvent;
import t2.client.events.RemoteAtCmdHandler;
import t2.client.events.SendDataEvent;
import t2.client.events.SendDataHandler;
import t2.client.events.XBeeInitEvent;
import t2.client.events.XBeeInitEventHandler;
import t2.client.rpc.RemoteAtCmd;
import t2.client.rpc.RemoteAtCmdAsync;
import t2.client.rpc.SendData;
import t2.client.rpc.SendDataAsync;
import t2.client.rpc.XBeeInit;
import t2.client.rpc.XBeeInitAsync;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.RootPanel;


public class T2 implements EntryPoint {


    public static EventBus EVENT_BUS = GWT.create(SimpleEventBus.class);


    @Override
    public void onModuleLoad() {
        final String port = "COM4";
        RootPanel.get().setPixelSize(Window.getClientHeight(), Window.getClientWidth());

        final MainTabPanel mainTabPanel = new MainTabPanel();
        // final int[] dest64 = { 0, 0x13, 0xa2, 0, 0x40, 0x76, 0x35, 0x0e };


        /* Put the series of commands which should be executed after init here. */
        final Queue<LocalATcmdEvent> localCommands = new LinkedList<LocalATcmdEvent>();
        localCommands.add(new LocalATcmdEvent("SL"));
        localCommands.add(new LocalATcmdEvent("NC"));


        /* Start services for RPC communication between client browser & host server. */
        final XBeeInitAsync initService = (XBeeInitAsync) GWT.create(XBeeInit.class);
        final SendDataAsync sendDataSvc = (SendDataAsync) GWT.create(SendData.class);
        final RemoteAtCmdAsync remoteAtCmdSvc = (RemoteAtCmdAsync) GWT.create(RemoteAtCmd.class);


        /* Use EventBus to synchronize the service calls which run on the server.  They are
         * kicked off here by the client.  Synchronization is a requirement because the XBee
         * must be initialized and the comms port must be opened and stay open before other
         * services can run or else they'll fire exceptions. */
        T2.EVENT_BUS.addHandler(XBeeInitEvent.TYPE, new XBeeInitEventHandler() {

            @Override
            public void checkStatus(XBeeInitEvent event) {

                initService.xbeeInit(event.getPort(), new AsyncCallback<String>() {
                    @Override
                    public void onFailure(Throwable caught) {}

                    @Override
                    public void onSuccess(String result) {
                        /* Kick off the rest of the events by starting with
                         * a Node Identifer command.  The remaining commands will
                         * be read from the queue. */
                        T2.EVENT_BUS.fireEvent(new LocalATcmdEvent("NI"));
                    }
                });
            }
        });


        /* The bus for local ATcmd traffic between XBeePanels and here. */
        T2.EVENT_BUS.addHandler(LocalATcmdEvent.TYPE, new LocalATcmdEventHandler() {

            @Override
            public void processATcmdEvent(LocalATcmdEvent event) {

                /* Listen for response traffic from the XBee, and fire the events
                 * in the commands queue in order. */
                if (event.isResponse()) {

                    if (!localCommands.isEmpty()) {
                        T2.EVENT_BUS.fireEvent(localCommands.poll());
                    }

                } else {
                    if (event.getCommand() == "ND") {
                        Window.alert("ND detected in main.");
                    }
                }
            }
        });


        /* Handler for Remote AT queries/commands. */
        T2.EVENT_BUS.addHandler(RemoteAtCmdEvent.TYPE, new RemoteAtCmdHandler() {
            @Override
            public void sendRemoteAtRequest(RemoteAtCmdEvent event) {
                if (event.getParam() == 0xFFFF) {
                    remoteAtCmdSvc.remoteATquery(event.getDest64(), event.getCommand(), new AsyncCallback<String>() {
                        @Override
                        public void onFailure(Throwable caught) {}

                        @Override
                        public void onSuccess(String result) {
                            Window.alert("Success." + result);
                        }
                    });
                } else {
                    Window.alert("Sending " + event.getCommand().toString() + String.valueOf(event.getParam()));
                    remoteAtCmdSvc.remoteATconfig(event.getDest64(), event.getCommand(), event.getParam(),
                            new AsyncCallback<String>() {
                                @Override
                                public void onFailure(Throwable caught) {}

                                @Override
                                public void onSuccess(String result) {
                                    Window.alert("Success." + result);
                                }
                            });
                }
            }
        });


        /* Handler for raw data traffic. On the receiving end, this data will show up on Pin 1. */
        T2.EVENT_BUS.addHandler(SendDataEvent.TYPE, new SendDataHandler() {
            @Override
            public void txData(SendDataEvent event) {
                if (event.getSource() == mainTabPanel.getButtonData()) {
                    sendDataSvc.transmit(event.getAddr64(), event.getPayload(), new AsyncCallback<String>() {
                        @Override
                        public void onFailure(Throwable caught) {}

                        @Override
                        public void onSuccess(String result) {}
                    });
                } else {
                    sendDataSvc.transmitExplicit(event.getFrameId(), event.getAddr64(), event.getAddr16(),
                            event.getPayload(), event.getSourceEndpoint(), event.getDestEndpoint(),
                            new AsyncCallback<String>() {

                                @Override
                                public void onFailure(Throwable caught) {}

                                @Override
                                public void onSuccess(String result) {}
                            });
                }
            }
        });


        RootPanel.get().add(mainTabPanel);

        /* Now that things are in place, kick off the events. */
        T2.EVENT_BUS.fireEvent(new XBeeInitEvent(port));
    }/* End onModuleLoad */

}